package drds.plus.parser.parser;

import drds.plus.parser.abstract_syntax_tree.expression.Expression;
import drds.plus.parser.abstract_syntax_tree.expression.Pair;
import drds.plus.parser.abstract_syntax_tree.statement.QueryStatement;
import drds.plus.parser.abstract_syntax_tree.statement.SelectStatement;
import drds.plus.parser.abstract_syntax_tree.statement.UnionStatement;
import drds.plus.parser.abstract_syntax_tree.statement.select.GroupBy;
import drds.plus.parser.abstract_syntax_tree.statement.select.Limit;
import drds.plus.parser.abstract_syntax_tree.statement.select.OrderBy;
import drds.plus.parser.abstract_syntax_tree.statement.select.table.Tables;
import drds.plus.parser.lexer.Lexer;
import drds.plus.parser.lexer.Token;
import drds.plus.parser.parser.dml.DmlParser;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class SelectParser extends DmlParser {

    public SelectParser(Lexer lexer, ExpressionParser expressionParser) {
        super(lexer, expressionParser);
        this.expressionParser.setSelectParser(this);
    }

    private List<Pair<Expression, String>> selectItemList() {
        Expression expression = expressionParser.expression();
        String alias = alias();
        //
        List<Pair<Expression, String>> list = null;
        if (lexer.token() != Token.PUNC_COMMA) {
            list = new ArrayList<Pair<Expression, String>>(1);
            list.add(new Pair<Expression, String>(expression, alias));
            return list;
        } else {
            list = new LinkedList<Pair<Expression, String>>();
            list.add(new Pair<Expression, String>(expression, alias));
            while (lexer.token() == Token.PUNC_COMMA) {
                lexer.nextToken();
                expression = expressionParser.expression();
                alias = alias();
                list.add(new Pair<Expression, String>(expression, alias));
            }
            list = new ArrayList<Pair<Expression, String>>(list);
            return list;
        }

    }

    public SelectStatement selectStatement() {


        Tables tables = null;
        Expression where = null;
        GroupBy groupBy = null;
        Expression having = null;
        OrderBy orderBy = null;
        Limit limit = null;
        //
        //第一个是select,所以需要进行nextToken()
        match(Token.KW_SELECT);
        lexer.nextToken();
        List<Pair<Expression, String>> selectItemList = selectItemList();
        match(Token.KW_FROM);
        lexer.nextToken();
        tables = tables();
        if (lexer.token() == Token.KW_WHERE) {
            lexer.nextToken();
            where = expressionParser.expression();
        }
        if (lexer.token() == Token.KW_GROUP) {
            groupBy = groupBy();
            if (lexer.token() == Token.KW_HAVING) {
                lexer.nextToken();
                having = expressionParser.expression();
            }
        }
        if (lexer.token() == Token.KW_ORDER) {
            orderBy = orderBy();
        }
        if (lexer.token() == Token.KW_OFFSET) {
            limit = limit();
        }
        boolean lockInShareMode = false;
        boolean forUpdate = false;
        switch (lexer.token()) {
            case KW_FOR:
                lexer.nextToken();
                match(Token.KW_UPDATE);
                forUpdate = true;
                break;
            case KW_LOCK:
                lexer.nextToken();
                match(Token.KW_IN);
                lexer.nextToken();
                match(Token.KW_SHARE);
                lexer.nextToken();
                match(Token.KW_MODE);
                lockInShareMode = true;
                break;
        }
        SelectStatement selectStatement = new SelectStatement(selectItemList, tables, where, groupBy, having, orderBy, limit);
        selectStatement.setLockInShareMode(lockInShareMode);
        selectStatement.setForUpdate(forUpdate);
        return selectStatement;
    }

    public QueryStatement union() {
        SelectStatement selectStatement = trySelectStatement();
        lexer.nextToken();//跳过)
        QueryStatement queryStatement = union(selectStatement);
        if (queryStatement instanceof UnionStatement) {
            UnionStatement unionStatement = (UnionStatement) queryStatement;
            if (lexer.token() == Token.KW_ORDER) {
                OrderBy orderBy = orderBy();
                unionStatement.setOrderBy(orderBy);
            }
            if (lexer.token() == Token.KW_OFFSET) {
                Limit limit = limit();
                unionStatement.setLimit(limit);
            }
        }
        return queryStatement;
    }

}
